package projects.ufam.nodes.nodeImplementations;

import projects.defaultProject.nodes.nodeImplementations.LocalizableNode;
import projects.defaultProject.nodes.timers.MessageTimer;
import projects.defaultProject.nodes.timers.WaitTimer;
import projects.ufam.CustomGlobal;
import projects.ufam.nodes.messages.A3HelloMessage;
import projects.ufam.nodes.messages.A3ParentRecognitionMessage;
import sinalgo.nodes.Node;
import sinalgo.nodes.NodeState;
import sinalgo.nodes.messages.Message;
import sinalgo.runtime.Global;

public class A3ModifiedNode extends A3Node implements Comparable {
	int count = 1;
	Node last = null;

	public A3ModifiedNode() {
		
	}

	protected void handleHello(Message msg, Node sender) {
		A3Node n = (A3Node) sender;
		if (parent == null) {
			this.parent = n;
			A3ParentRecognitionMessage m = new A3ParentRecognitionMessage();
			this.send(m, sender);
		} else {
			if (this.parent.compareTo(n) > 0) {
				this.parent = n;
				A3ParentRecognitionMessage m = new A3ParentRecognitionMessage();
				this.send(m, sender);
			}
		}
	}

	public void preStep() {
		super.preStep();
		redundance = CustomGlobal.kCoverage;
		if (Global.currentTime % CustomGlobal.densityControlRoundLength == 0) {
			last = null;
		}
	}

	/*
	 * Method to ensure that a node won't be "forgotten" (non-Javadoc)
	 * 
	 * @see
	 * projects.defaultProject.nodes.nodeImplementations.LocalizableNode#postStep
	 * ()
	 */
	public void postStep() {
		super.postStep();
		if ((int) count
				% (int) ((int) CustomGlobal.densityControlRoundLength / 10) == 0) {
			// this.switchState(NodeState.StandBy);
			if (last != null && this.getState() == NodeState.WakingUp) {
				this.switchState(NodeState.Enabled);
				A3HelloMessage msg = new A3HelloMessage();
				MessageTimer t = new MessageTimer(msg);
				covered = true;
				t.startRelative(5, this);
				if (wt != null)
					wt.setEnabled(false);
				wt = new WaitTimer(null);
				wt.startRelative(10, this);
				a3State = A3State.WaitingChildren;
			}
		}
		if (getState() == NodeState.WakingUp) {
			count++;
		} else
			count = 1;
	}

	public boolean shouldHandle(Message msg, Node sender) {
		double d = this.estimateDistance(sender);
		if (d > CustomGlobal.sensorRange && msg instanceof A3HelloMessage) {
			last = sender;
		}
		return d < CustomGlobal.sensorRange;
	}
	
	@Override
	public int compareTo(Object o) {
		LocalizableNode o2 = (LocalizableNode) o;
		int c = o2.ID > this.ID ? -1 : 1;
		if (o == null || this.parent == null)
			return c;
		
		double d1 = this.parent.estimateDistance(o2);
		double d2 = this.parent.estimateDistance(this);
		double we = 1.0;
		double wd = CustomGlobal.sensorRange;
		d1 = d1 * wd + we * ((LocalizableNode) o).getEnergyLevel();
		d2 = d2 * wd + we * this.getEnergyLevel();

		if (CustomGlobal.useResidualOnDC) {
			double r1 = this.getResidual() < 0.001 ? 0.001 : (this
					.getResidual() > 500 ? 10 : this.getResidual());

			double r2 = o2.getResidual() < 0.001 ? 0.001
					: (o2.getResidual() > 500 ? 10 : o2.getResidual());

			d1 = r1;
			d2 = r2;
		}

		return (d1 < d2 ? -1 : (d1 == d2 ? c : 1));
	}
}
